﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;

namespace SHomeWorkshop.LunarPresentation.Expressions
{
    public class Tree : CanvasExpression
    {
        public Tree(SubPanel rootPanel, SubPanel parentPanel, Editor editor)
            : base(rootPanel, parentPanel, editor)
        {
            this.chineseName = "树";
        }

        protected override void RefreshSubPanelRelatios()
        {
            //根据SuperLeafExID的值来刷新每个公式的“SubLeafs”列表。
            if (this.rootLeaf != null) this.rootLeaf.NextLevelLeaves.Clear();//这句应该是多余的！！

            for (int i = 0; i < this.Children.Count; i++)
            {
                if (this.Children[i] is LeafPanel == false) continue;
                LeafPanel leaf = this.Children[i] as LeafPanel;
                leaf.NextLevelLeaves.Clear();

                for (int j = 0; j < this.Children.Count; j++)
                {
                    if (j == i) continue;//一个叶不可能是自身的下级叶。

                    if (this.Children[j] is LeafPanel == false) continue;

                    LeafPanel elseLeaf = this.Children[j] as LeafPanel;
                    if (elseLeaf.PreLevelLeafExID == leaf.ExID)
                    {
                        leaf.NextLevelLeaves.Add(elseLeaf);
                    }
                }
            }

            for (int i = 0; i < this.Children.Count; i++)
            {
                if (this.Children[i] is LeafPanel == false) continue;
                LeafPanel leaf = this.Children[i] as LeafPanel;
                SortNextLevelleaves(leaf);
            }
        }

        public static readonly double defWidthOfLinesArea = 30;

        /// <summary>
        /// TODO 要根据“Index”来对每一个叶的子叶进行排序。
        /// ——这将决定每个子叶的纵坐标。
        /// </summary>
        /// <param name="leaf"></param>
        private void SortNextLevelleaves(LeafPanel leaf)
        {
            if (leaf.NextLevelLeaves.Count <= 0) return;

            leaf.NextLevelLeaves.Sort(new LeafIndexCompare());
        }

        public override Brush ExForeground
        {
            get
            {
                return base.ExForeground;
            }
            set
            {
                UpdateExForegroundWithoutXmlChanging(value);
                UpdateExForegroundToXmlData(value);
                Editor.IsModified = true;
            }
        }

        public override void UpdateExForegroundWithoutXmlChanging(Brush value)
        {
            base.UpdateExForegroundWithoutXmlChanging(value);

            //base.exForeground = value;//基类方法中有。
            DrawLines();
        }

        private LeafPanel rootLeaf;

        /// <summary>
        /// 叶首面板。每个树只有一个。不允许删除！！
        /// </summary>
        public LeafPanel RootLeaf
        {
            get { return rootLeaf; }
        }

        /// <summary>
        /// 与“尾子面板”，都指向叶首面板。
        /// </summary>
        public override SubPanel FirstSubPanel
        {
            get
            {
                return this.rootLeaf;
            }
        }

        /// <summary>
        /// 与“首子面板”，都指向叶首面板。
        /// </summary>
        public override SubPanel LastSubPanel
        {
            get
            {
                return this.rootLeaf;
            }
        }

        protected override void BuildChildren()
        {
            this.subPanels.Clear();

            base.BuildChildren();

            if (this.XmlData == null) return;

            XmlNodeList childrenNodes = this.XmlData.SelectNodes("Expression");

            if (childrenNodes == null || childrenNodes.Count <= 0) return;

            foreach (XmlNode node in childrenNodes)
            {
                XmlAttribute attrType = node.GetAttribute("Type");
                if (attrType != null && attrType.Value == "LeafPanel")
                {
                    LeafPanel leaf = new LeafPanel(this.rootPanel, this.ParentPanel,
                        this.editor, this);

                    this.basePanel.Children.Add(leaf);
                    this.subPanels.Add(leaf);
                    leaf.XmlData = node;

                    if (leaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        this.rootLeaf = leaf;
                    }

                    leaf.SizeChanged += new SizeChangedEventHandler(leaf_SizeChanged);
                }
            }

            XmlAttribute attrLineType = this.XmlData.GetAttribute("LineType");
            if (attrLineType != null)
            {
                this.lineType = (TreeLineType)Enum.Parse(typeof(TreeLineType), attrLineType.Value);
                this.DrawLines();
            }

            //已有leaf_SizeChanged事件中的RefreshLayout(false);不必重复。
            RefreshSubPanelRelatios();
        }

        void leaf_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            RefreshLayout(false);
        }

        /// <summary>
        /// 在递归过程中应判断有无必要调用CollapseNextLevelLeaves()方法。
        /// </summary>
        /// <param name="leaf"></param>
        private void ShowNextLevelLeaves(LeafPanel leaf)
        {
            if (leaf == null) return;

            if (leaf.LeafType == LeafPanel.LeafPanelType.Root)//叶首面板总是不折叠的。
            {
                foreach (LeafPanel lp in leaf.NextLevelLeaves)
                {
                    ShowNextLevelLeaves(lp);

                    if (lp.Visibility != Visibility.Visible)
                    {
                        lp.Visibility = Visibility.Visible;
                    }
                }
            }
            else
            {
                foreach (LeafPanel lp in leaf.NextLevelLeaves)
                {
                    if (leaf.IsCollapsed)
                    {
                        CollapseNextLevelLeaves(lp);
                    }
                    else
                    {
                        ShowNextLevelLeaves(lp);
                    }
                }

                if (leaf.Visibility != Visibility.Visible)
                {
                    leaf.Visibility = Visibility.Visible;
                }
            }
        }

        /// <summary>
        /// 此方法只应由ShowNextLevelLeaves()或本身调用。且必须在循环中调用。
        /// 因为一旦某个叶被设置为“折叠”，其下级的所有叶都不应显示。
        /// </summary>
        /// <param name="willCollapseLeaf"></param>
        private void CollapseNextLevelLeaves(LeafPanel willCollapseLeaf)
        {
            if (willCollapseLeaf == null) return;

            foreach (LeafPanel lp in willCollapseLeaf.NextLevelLeaves)
            {
                CollapseNextLevelLeaves(lp);
            }

            if (willCollapseLeaf.Visibility != Visibility.Collapsed)
            {
                willCollapseLeaf.Visibility = Visibility.Collapsed;
            }
        }

        /// <summary>
        /// 重新排列各子面板。
        /// </summary>
        public void RefreshLayout(bool refreshRelationsFst = true)
        {
            if (refreshRelationsFst)
            {
                RefreshSubPanelRelatios();
            }

            //从RootLeaf开始，先递归判断是显示还是隐藏叶。
            ShowNextLevelLeaves(this.rootLeaf);

            // 递归计算每个叶面板需要的尺寸。
            // 其中，叶首面板要分“左”、“右”两大部分来比较。

            if (this.rootLeaf == null)
            {
                this.basePanel.Width = 40; this.basePanel.Height = 20;
                return;
            }

            if (this.rootLeaf.NextLevelLeaves.Count <= 0)
            {
                this.basePanel.Width = this.rootLeaf.ActualWidth + 20
                    + this.rootLeaf.Margin.Left
                    + this.rootLeaf.Margin.Right;
                this.basePanel.Height = this.rootLeaf.ActualHeight + 20
                    + this.rootLeaf.Margin.Top
                    + this.rootLeaf.Margin.Bottom;

                //LeafPanel的margin是4。
                Canvas.SetLeft(this.rootLeaf, 10);
                Canvas.SetTop(this.rootLeaf, 10);

                DrawLines();
                return;
            }

            double leftWidth = 0;
            double rightWidth = 0;
            double leftHeight = 0;
            double rightHeight = 0;

            // 先算出叶首面板所有“下级叶”的尺寸。
            foreach (LeafPanel leaf in this.rootLeaf.NextLevelLeaves)
            {
                Size s = GetAndRefreshNeedSize(leaf);
                switch (leaf.LeafType)
                {
                    case LeafPanel.LeafPanelType.Left:
                        {
                            if (s.Width > leftWidth)
                            {
                                leftWidth = s.Width;
                            }

                            leftHeight += s.Height;
                            break;
                        }
                    case LeafPanel.LeafPanelType.Right:
                        {
                            if (s.Width > rightWidth)
                            {
                                rightWidth = s.Width;
                            }

                            rightHeight += s.Height;
                            break;
                        }
                }
            }

            if (leftWidth > 0) leftWidth += defWidthOfLinesArea;//如果左侧存在叶首面板的直接子叶。
            if (rightWidth > 0) rightWidth += defWidthOfLinesArea;

            this.basePanel.Width = this.rootLeaf.RenderSize.Width +
                this.rootLeaf.Margin.Left + this.rootLeaf.Margin.Right +
                leftWidth + rightWidth + 20;
            double dHeight1 = leftHeight > rightHeight ? leftHeight : rightHeight;
            double dHeight2 = this.rootLeaf.RenderSize.Height
                + this.rootLeaf.Margin.Top + this.rootLeaf.Margin.Bottom;

            this.basePanel.Height = dHeight1 > dHeight2 ? (dHeight1 + 20) : (dHeight2 + 20);

            Canvas.SetLeft(this.rootLeaf, leftWidth + 10);

            double halfOfTwoHeights = Math.Abs(leftHeight - rightHeight) / 2;

            //循环，设置叶首面板的每一个子叶的位置。
            //不直接从叶首面板开始递归——这是因为叶首面板分左右。而其它叶则有固定的左右方向。
            double sumHeight = 10 - this.rootLeaf.Margin.Top;
            if (rightHeight < leftHeight) sumHeight += halfOfTwoHeights;

            //与普通叶不同，叶首面板的分支分左、右两侧，需要分别计算纵坐标。
            //因此这里要分开，用两个循环。
            //先设置叶首面板右侧各分支。
            for (int i = 0; i < this.rootLeaf.NextLevelLeaves.Count; i++)
            {
                LeafPanel lf = this.rootLeaf.NextLevelLeaves[i];
                if (lf.LeafType == LeafPanel.LeafPanelType.Right)
                {
                    RefreshLeafLocation(lf, sumHeight);
                    sumHeight += lf.NeedSize.Height;
                }
            }

            sumHeight = 10 - this.rootLeaf.Margin.Top;
            if (leftHeight < rightHeight) sumHeight += halfOfTwoHeights;

            //再设置叶首面板左侧各分支。
            for (int i = 0; i < this.rootLeaf.NextLevelLeaves.Count; i++)
            {
                LeafPanel lf = this.rootLeaf.NextLevelLeaves[i];
                if (lf.LeafType == LeafPanel.LeafPanelType.Left)
                {
                    RefreshLeafLocation(lf, sumHeight);
                    sumHeight += lf.NeedSize.Height;
                }
            }

            Canvas.SetTop(this.rootLeaf,
                (this.basePanel.Height - this.rootLeaf.RenderSize.Height) / 2 - 4);

            // 画分支线。
            DrawLines();
        }

        private List<Path> lines = new List<Path>();

        private void DrawLines()
        {
            foreach (Path path in lines)
            {
                if (this.basePanel.Children.Contains(path))
                {
                    this.basePanel.Children.Remove(path);
                }
            }

            lines.Clear();

            if (this.rootLeaf == null || this.rootLeaf.NextLevelLeaves.Count <= 0) return;


            //还是从叶首面板起绘制。考虑到将来可能更改实现，也分左、右两侧。

            //下面从叶首面板的所有直接子叶开始绘制。
            //先绘制右边各一级分支的线。
            for (int i = 0; i < this.rootLeaf.NextLevelLeaves.Count; i++)
            {
                LeafPanel leaf = this.rootLeaf.NextLevelLeaves[i];
                if (leaf.LeafType == LeafPanel.LeafPanelType.Right)
                {
                    switch (this.lineType)
                    {
                        case TreeLineType.Default:
                            {
                                DrawRightLine_Default(this.rootLeaf, lines); break;
                            }
                        case TreeLineType.Single:
                            {
                                DrawRightLine_Single(this.rootLeaf, lines); break;
                            }
                        case TreeLineType.Orgnization:
                            {
                                DrawRightLine_Orgnization(this.rootLeaf, lines); break;
                            }
                    }

                    //令右侧的某个直接子叶绘制其曲线。
                    DrawLine(leaf, ref lines);
                }
            }

            //再绘制左边各一级分支的线。
            for (int i = 0; i < this.rootLeaf.NextLevelLeaves.Count; i++)
            {
                LeafPanel leaf = this.rootLeaf.NextLevelLeaves[i];
                if (leaf.LeafType == LeafPanel.LeafPanelType.Left)
                {
                    switch (this.lineType)
                    {
                        case TreeLineType.Default:
                            {
                                DrawLeftLine_Default(this.rootLeaf, lines); break;
                            }
                        case TreeLineType.Single:
                            {
                                DrawLeftLine_Single(this.rootLeaf, lines); break;
                            }
                        case TreeLineType.Orgnization:
                            {
                                DrawLeftLine_Orgnization(this.rootLeaf, lines); break;
                            }
                    }

                    //令左侧的某个直接子叶绘制其曲线。
                    DrawLine(leaf, ref lines);
                }
            }
        }

        public enum TreeLineType { Default, Orgnization, Single }

        private TreeLineType lineType = TreeLineType.Default;

        public TreeLineType LineType
        {
            get { return lineType; }
            set
            {
                lineType = value;
                this.XmlData.SetAttribute("LineType", value.ToString());
                RefreshLayout(false);
            }
        }

        /// <summary>
        /// 应递归调用本方法。
        /// </summary>
        /// <param name="preLevelLeaf">从此叶向下级各叶绘制。</param>
        /// <param name="lines"></param>
        private void DrawLine(LeafPanel preLevelLeaf, ref List<Path> lines)
        {
            if (preLevelLeaf == null || preLevelLeaf.NextLevelLeaves.Count <= 0 ||
                preLevelLeaf.IsCollapsed) return;

            switch (preLevelLeaf.LeafType)
            {
                case LeafPanel.LeafPanelType.Right:
                    {
                        switch (this.lineType)
                        {
                            case TreeLineType.Default:
                                {
                                    DrawRightLine_Default(preLevelLeaf, lines); break;
                                }
                            case TreeLineType.Orgnization:
                                {
                                    DrawRightLine_Orgnization(preLevelLeaf, lines); break;
                                }
                            case TreeLineType.Single:
                                {
                                    DrawRightLine_Single(preLevelLeaf, lines); break;
                                }
                        }

                        foreach (LeafPanel slp in preLevelLeaf.NextLevelLeaves)
                        {
                            DrawLine(slp, ref lines);
                        }
                        break;
                    }
                case LeafPanel.LeafPanelType.Left:
                    {
                        switch (this.lineType)
                        {
                            case TreeLineType.Default:
                                {
                                    DrawLeftLine_Default(preLevelLeaf, lines); break;
                                }
                            case TreeLineType.Orgnization:
                                {
                                    DrawLeftLine_Orgnization(preLevelLeaf, lines); break;
                                }
                            case TreeLineType.Single:
                                {
                                    DrawLeftLine_Single(preLevelLeaf, lines); break;
                                }
                        }

                        foreach (LeafPanel slp in preLevelLeaf.NextLevelLeaves)
                        {
                            DrawLine(slp, ref lines);
                        }
                        break;
                    }
            }
        }

        private void DrawLeftLine_Single(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80, SnapsToDevicePixels = true };
            myPath.StrokeStartLineCap = PenLineCap.Square;
            myPath.StrokeEndLineCap = PenLineCap.Square;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Bevel;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Aliased);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;
            Point centerPt;

            if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {
                startPt = new Point(Canvas.GetLeft(preLevelLeaf)
                        + preLevelLeaf.Margin.Left,
                    Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2 +
                        preLevelLeaf.Margin.Top);
            }
            else
            {
                startPt = new Point(Canvas.GetLeft(preLevelLeaf)
                        + preLevelLeaf.Margin.Left,
                    Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight +
                        preLevelLeaf.Margin.Top + 2);
            }

            centerPt = new Point((int)(startPt.X - defWidthOfLinesArea / 2), startPt.Y);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Left) continue;
                    }

                    if (subLeaf.NextLevelLeaves.Count > 0)
                    {
                        sLineA.X = (int)(Canvas.GetLeft(subLeaf) + subLeaf.Margin.Left - defWidthOfLinesArea / 2) + 1;
                    }
                    else
                    {
                        sLineA.X = (int)(Canvas.GetLeft(subLeaf) + subLeaf.Margin.Left) + 1;
                    }

                    sLineA.Y = (int)(Canvas.GetTop(subLeaf) +
                        subLeaf.Margin.Top + subLeaf.ActualHeight) + 2;
                    sLineB.X = centerPt.X;
                    sLineB.Y = sLineA.Y;

                    ctx.BeginFigure(sLineA, false, false);
                    ctx.LineTo(sLineB, true, true);
                    ctx.LineTo(centerPt, true, true);

                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        ctx.LineTo(startPt, true, true);
                    }
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void DrawLeftLine_Orgnization(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80 };
            myPath.StrokeStartLineCap = PenLineCap.Round;
            myPath.StrokeEndLineCap = PenLineCap.Round;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Aliased);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;
            Point centerPt;

            startPt = new Point(Canvas.GetLeft(preLevelLeaf)
                    + preLevelLeaf.Margin.Left,
                Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2 +
                    preLevelLeaf.Margin.Top);

            centerPt = new Point(startPt.X - defWidthOfLinesArea / 2, startPt.Y);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Left) continue;
                    }

                    sLineA.X = Canvas.GetLeft(subLeaf) + subLeaf.ActualWidth + subLeaf.Margin.Right;
                    sLineA.Y = Canvas.GetTop(subLeaf) +
                        +subLeaf.Margin.Top + subLeaf.ActualHeight / 2;
                    sLineB.X = centerPt.X;
                    sLineB.Y = sLineA.Y;

                    ctx.BeginFigure(startPt, false, false);
                    ctx.LineTo(centerPt, true, true);
                    ctx.LineTo(sLineB, true, true);
                    ctx.LineTo(sLineA, true, true);

                    Point ptrb = new Point(sLineA.X, sLineA.Y + subLeaf.ActualHeight / 2);
                    Point ptlb = new Point(Canvas.GetLeft(subLeaf) + subLeaf.Margin.Left, ptrb.Y);
                    Point ptlt = new Point(ptlb.X, Canvas.GetTop(subLeaf) + subLeaf.Margin.Top);
                    Point ptrt = new Point(ptrb.X, ptlt.Y);

                    ctx.BeginFigure(ptrb, false, false);
                    ctx.PolyLineTo(new List<Point>() { ptrb, ptlb, ptlt, ptrt, ptrb }, true, true);
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void DrawRightLine_Single(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80, SnapsToDevicePixels = true };

            myPath.StrokeStartLineCap = PenLineCap.Round;
            myPath.StrokeEndLineCap = PenLineCap.Round;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Aliased);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;
            Point centerPt;

            if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {
                startPt = new Point(
                Canvas.GetLeft(preLevelLeaf) + preLevelLeaf.ActualWidth
                    + preLevelLeaf.Margin.Left,
                Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2
                    + preLevelLeaf.Margin.Top);
            }
            else
            {
                startPt = new Point(
                Canvas.GetLeft(preLevelLeaf) + preLevelLeaf.ActualWidth
                    + preLevelLeaf.Margin.Left,
                Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight +
                    preLevelLeaf.Margin.Top + 2);
            }

            centerPt = new Point(startPt.X + defWidthOfLinesArea / 2, startPt.Y);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Right) continue;
                    }

                    sLineA.X = centerPt.X;
                    sLineA.Y = Canvas.GetTop(subLeaf) +
                        subLeaf.Margin.Top + subLeaf.ActualHeight + 2;

                    if (subLeaf.NextLevelLeaves.Count > 0)
                    {
                        sLineB.X = Canvas.GetLeft(subLeaf) + subLeaf.ActualWidth +
                            subLeaf.Margin.Left + defWidthOfLinesArea / 2;
                    }
                    else
                    {
                        sLineB.X = Canvas.GetLeft(subLeaf) + subLeaf.ActualWidth +
                            subLeaf.Margin.Left;
                    }

                    sLineB.Y = sLineA.Y;


                    //ctx.BeginFigure(startPt, false, false);
                    //ctx.LineTo(centerPt, true, true);
                    ctx.BeginFigure(centerPt, false, false);
                    ctx.LineTo(sLineA, true, true);
                    ctx.LineTo(sLineB, true, true);

                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        ctx.BeginFigure(startPt, false, false);
                        ctx.LineTo(centerPt, true, true);
                    }
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void DrawRightLine_Orgnization(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80 };

            myPath.StrokeStartLineCap = PenLineCap.Round;
            myPath.StrokeEndLineCap = PenLineCap.Round;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Aliased);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;
            Point centerPt;

            startPt = new Point(
            Canvas.GetLeft(preLevelLeaf) + preLevelLeaf.ActualWidth
                + preLevelLeaf.Margin.Left,
            Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2
                + preLevelLeaf.Margin.Top);

            centerPt = new Point(startPt.X + defWidthOfLinesArea / 2, startPt.Y);

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Right) continue;
                    }

                    sLineA.X = centerPt.X;
                    sLineA.Y = Canvas.GetTop(subLeaf) +
                        subLeaf.Margin.Top + subLeaf.ActualHeight / 2;
                    sLineB.X = Canvas.GetLeft(subLeaf) + subLeaf.Margin.Left;
                    sLineB.Y = sLineA.Y;

                    ctx.BeginFigure(startPt, false, false);
                    ctx.LineTo(centerPt, true, true);
                    ctx.LineTo(sLineA, true, true);
                    ctx.LineTo(sLineB, true, true);

                    Point ptlt = new Point(sLineB.X, Canvas.GetTop(subLeaf) + subLeaf.Margin.Top);
                    Point ptrt = new Point(ptlt.X + subLeaf.ActualWidth, ptlt.Y);
                    Point ptrb = new Point(ptrt.X, ptlt.Y + subLeaf.ActualHeight);
                    Point ptlb = new Point(ptlt.X, ptrb.Y);

                    ctx.BeginFigure(ptlt, false, false);
                    ctx.PolyLineTo(new List<Point>() { ptlt, ptrt, ptrb, ptlb, ptlt }, true, true);
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void DrawRightLine_Default(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80 };

            myPath.StrokeStartLineCap = PenLineCap.Round;
            myPath.StrokeEndLineCap = PenLineCap.Round;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Unspecified);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;

            if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {
                startPt = new Point(
                Canvas.GetLeft(preLevelLeaf) + preLevelLeaf.ActualWidth
                    + preLevelLeaf.Margin.Left,
                Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2
                    + preLevelLeaf.Margin.Top);
            }
            else
            {
                startPt = new Point(
                Canvas.GetLeft(preLevelLeaf) + preLevelLeaf.ActualWidth
                    + preLevelLeaf.Margin.Left,
                Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight +
                    preLevelLeaf.Margin.Top + 2);
            }

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();
                Point bLineACtrl = new Point() { X = startPt.X + 15 };
                Point bLineBCtrl = new Point()
                {
                    X = startPt.X + 15,
                    Y = startPt.Y
                };

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Right) continue;
                    }

                    sLineA.X = Canvas.GetLeft(subLeaf);
                    sLineA.Y = Canvas.GetTop(subLeaf) +
                        subLeaf.Margin.Top + subLeaf.ActualHeight + 2;
                    sLineB.X = sLineA.X + subLeaf.ActualWidth +
                        subLeaf.Margin.Left;
                    sLineB.Y = sLineA.Y;

                    bLineACtrl.Y = sLineA.Y;

                    ctx.BeginFigure(startPt, false, false);
                    ctx.BezierTo(bLineBCtrl, bLineACtrl, sLineA, true, true);
                    ctx.LineTo(sLineB, true, true);
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void DrawLeftLine_Default(LeafPanel preLevelLeaf, List<Path> lines)
        {
            Path myPath = new Path() { Opacity = 80 };
            myPath.StrokeStartLineCap = PenLineCap.Round;
            myPath.StrokeEndLineCap = PenLineCap.Round;
            myPath.Stroke = this.ExForeground;
            //myPath.Fill = Brushes.Blue;
            myPath.StrokeThickness = 2;
            myPath.StrokeLineJoin = PenLineJoin.Round;
            RenderOptions.SetEdgeMode(myPath, EdgeMode.Unspecified);

            StreamGeometry geometry = new StreamGeometry();

            Point startPt;

            if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {
                startPt = new Point(Canvas.GetLeft(preLevelLeaf)
                        + preLevelLeaf.Margin.Left,
                    Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight / 2 +
                        preLevelLeaf.Margin.Top);
            }
            else
            {
                startPt = new Point(Canvas.GetLeft(preLevelLeaf)
                        + preLevelLeaf.Margin.Left,
                    Canvas.GetTop(preLevelLeaf) + preLevelLeaf.ActualHeight +
                        preLevelLeaf.Margin.Top + 2);
            }

            using (StreamGeometryContext ctx = geometry.Open())
            {
                Point sLineA = new Point();
                Point sLineB = new Point();
                Point bLineACtrl = new Point() { X = startPt.X - 15 };
                Point bLineBCtrl = new Point()
                {
                    X = startPt.X - 15,
                    Y = startPt.Y
                };

                foreach (LeafPanel subLeaf in preLevelLeaf.NextLevelLeaves)
                {
                    if (preLevelLeaf.LeafType == LeafPanel.LeafPanelType.Root)
                    {
                        if (subLeaf.LeafType != LeafPanel.LeafPanelType.Left) continue;
                    }

                    sLineA.X = Canvas.GetLeft(subLeaf) + subLeaf.Margin.Left;
                    sLineA.Y = Canvas.GetTop(subLeaf) +
                        +subLeaf.Margin.Top + subLeaf.ActualHeight + 2;
                    sLineB.X = sLineA.X + subLeaf.ActualWidth;
                    sLineB.Y = sLineA.Y;

                    bLineACtrl.Y = sLineA.Y;

                    ctx.BeginFigure(startPt, false, false);
                    ctx.BezierTo(bLineBCtrl, bLineACtrl, sLineB, true, true);
                    ctx.LineTo(sLineA, true, true);
                }
            }

            myPath.Data = geometry;
            Canvas.SetZIndex(myPath, 0);
            lines.Add(myPath);
            this.basePanel.Children.Add(myPath);
        }

        private void RefreshLeafLocation(LeafPanel leaf, double startTop)
        {
            //左边是从“上级”的右边加３０开始。
            if (leaf == null) return;
            LeafPanel preLevelLeaf = leaf.PreLevelLeaf;
            if (preLevelLeaf == null) return;

            switch (leaf.LeafType)
            {
                case LeafPanel.LeafPanelType.Right:
                    {
                        Canvas.SetLeft(leaf,
                            Canvas.GetLeft(preLevelLeaf) +
                            preLevelLeaf.ActualWidth +
                            preLevelLeaf.Margin.Left +
                            preLevelLeaf.Margin.Right + defWidthOfLinesArea);
                        break;
                    }
                case LeafPanel.LeafPanelType.Left:
                    {
                        Canvas.SetLeft(leaf,
                            Canvas.GetLeft(preLevelLeaf) -
                            leaf.ActualWidth -
                            leaf.Margin.Left -
                            leaf.Margin.Right - defWidthOfLinesArea);
                        break;
                    }
            }

            startTop += preLevelLeaf.SurplusHalfHeight;

            if (leaf.IsCollapsed == false)
            {
                //如何确定主叶面板的直接子叶的纵坐标？？？
                double sumHeight = startTop;

                for (int i = 0; i < leaf.NextLevelLeaves.Count; i++)
                {
                    LeafPanel lf = leaf.NextLevelLeaves[i];
                    RefreshLeafLocation(lf, sumHeight);
                    sumHeight += lf.NeedSize.Height;
                }

            }

            if (leaf.PreLevelLeaf != null &&
                leaf.PreLevelLeaf.NextLevelLeaves.Count == 1 &&
                leaf.ActualHeight == leaf.PreLevelLeaf.ActualHeight)
            {
                Canvas.SetTop(leaf, Canvas.GetTop(leaf.PreLevelLeaf));
            }
            else
            {
                Canvas.SetTop(leaf, startTop + (leaf.NeedSize.Height - leaf.ActualHeight) / 2);
            }
        }

        private static Size zeroSize = new Size(0, 0);

        private Size GetAndRefreshNeedSize(LeafPanel leaf)
        {
            if (leaf == null) return zeroSize;

            if (leaf.NextLevelLeaves.Count <= 0 || leaf.IsCollapsed)
            {
                Size renderSize = leaf.RenderSize;
                leaf.NeedSize = new Size(
                    renderSize.Width + leaf.Margin.Left + leaf.Margin.Right,
                    renderSize.Height + leaf.Margin.Top + leaf.Margin.Bottom);

                return leaf.NeedSize;
            }

            Size sumSizeOfSubLeafs = new Size(0, 0);

            foreach (LeafPanel lf in leaf.NextLevelLeaves)
            {
                lf.NeedSize = GetAndRefreshNeedSize(lf);

                sumSizeOfSubLeafs.Height += lf.NeedSize.Height;
                if (lf.NeedSize.Width > sumSizeOfSubLeafs.Width)
                {
                    sumSizeOfSubLeafs.Width = lf.NeedSize.Width;
                }
            }

            double h, w;

            h = leaf.RenderSize.Height + leaf.Margin.Top + leaf.Margin.Bottom;
            if (h < sumSizeOfSubLeafs.Height)
            {
                h = sumSizeOfSubLeafs.Height;
            }

            leaf.SurplusHalfHeight = (h - sumSizeOfSubLeafs.Height) / 2;

            w = leaf.RenderSize.Width
                + leaf.Margin.Left + leaf.Margin.Right
                + sumSizeOfSubLeafs.Width + defWidthOfLinesArea;//defWidthOfLinesArea宽度用来画线。

            Size resultSize = new Size(w, h);
            leaf.NeedSize = resultSize; return leaf.NeedSize;
        }

        private bool isDeletingOrCutting = false;

        /// <summary>
        /// 删除本树中某个叶面板及其所有下级叶面板。
        /// </summary>
        /// <param name="leaf">要删除的叶面板。叶首面板不能被删除。</param>
        /// <param name="onlyDelete">是否只执行删除操作。</param>
        internal bool CutOrDeleteLeaf(LeafPanel leaf, ModifingItem mi, bool onlyDelete)
        {
            if (isDeletingOrCutting) return false;

            isDeletingOrCutting = true;//防止过快操作导致出错。

            if (leaf == null)
            {
                MessageBox.Show("要删除的叶面板不能为null！", Globals.appName,
                   MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }

            if (leaf == this.rootLeaf)
            {
                MessageBox.Show("不能删除树的叶首面板！", Globals.appName,
                   MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }

            if (leaf.ParentExpression != this)
            {
                MessageBox.Show("要删除的叶面板不在此树中！", Globals.appName,
                   MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }

            //还需要更改同层受影响的其它叶面板的索引。
            LeafPanel preLevelLeafPanel = leaf.PreLevelLeaf;

            if (preLevelLeafPanel == null)
            {
                MessageBox.Show("老问题，在删除时未找到同级其它叶面板！", Globals.appName,
                   MessageBoxButton.OK, MessageBoxImage.Warning);
                return false;
            }

            List<LeafPanel> preLeafNextLeves = preLevelLeafPanel.NextLevelLeaves;

            List<string> xmlTextLists = new List<string>();

            bool result = DeleteOneLeafAndNextLevelLeafs(leaf, mi, onlyDelete, xmlTextLists);

            if (result)
            {
                if (preLeafNextLeves.Contains(leaf))
                {
                    preLeafNextLeves.Remove(leaf);
                }

                if (leaf.Index < preLeafNextLeves.Count - 1)
                {
                    int maxIndexInSameLevel = 0;
                    foreach (LeafPanel brother in preLeafNextLeves)
                    {
                        if (brother.Index > leaf.Index)
                        {
                            maxIndexInSameLevel = brother.Index;
                        }
                    }

                    for (int i = leaf.Index + 1; i < maxIndexInSameLevel; i++)
                    {
                        LeafPanel lp = preLeafNextLeves[i];
                        Action actIndex = new Action(leaf.ExID, -1,
                            leaf.GetType().Name, "Index", lp.Index.ToString(),
                            (lp.Index - 1).ToString());
                        lp.Index -= 1;
                        mi.Add(actIndex);
                    }
                }

                RefreshLayout(false);

                if (!onlyDelete)
                {
                    StringBuilder sBuilder = new StringBuilder();

                    //注意：这里是逆序——被剪切的叶面板在首个。
                    for (int i = xmlTextLists.Count - 1; i >= 0; i--)
                    {
                        string s = xmlTextLists[i];
                        sBuilder.Append(s);
                    }

                    Clipboard.SetData(DataFormats.UnicodeText, "<TreeLeaves SourceTreeID=\"" + this.ExID + "\">"
                        + sBuilder.ToString() + "</TreeLeaves>");
                }
            }

            isDeletingOrCutting = false;

            return result;
        }

        /// <summary>
        /// 此方法用于递归删除。只应由自身或“DeleteLeaf()”调用。
        /// </summary>
        /// <param name="leaf"></param>
        /// <param name="mi"></param>
        /// <returns></returns>
        private bool DeleteOneLeafAndNextLevelLeafs(LeafPanel leaf, ModifingItem mi,
            bool onlyDelete, List<string> xmlTextLists)
        {
            LeafPanel preLevelLeaf = leaf.PreLevelLeaf;

            if (leaf == null) return false;

            if (leaf.NextLevelLeaves.Count > 0)
            {
                //有下级。先删除所有下级。
                foreach (LeafPanel lp in leaf.NextLevelLeaves)
                {
                    DeleteOneLeafAndNextLevelLeafs(lp, mi, onlyDelete, xmlTextLists);
                }
            }

            //再删除自身。
            Action actDelLeaf = new Action(
                leaf.ExID,//叶面板ID
                -1,//叶面板索引，无必要——删除前的数据中有。
                null,//属性名，无必要。
                leaf.GetType().Name,//类名，备用。
                leaf.XmlData.OuterXml,//删除前的数据。
                null,//删除后的数据，空。
                ActionType.CutOrDeleteTreeLeaf,//操作类型。
                leaf.ParentExpression.ExID//所在公式（某个“树”）的ID。
                );

            this.basePanel.Children.Remove(leaf);

            if (this.subPanels.Contains(leaf))
            {
                this.subPanels.Remove(leaf);
            }

            if (!onlyDelete && leaf.XmlData != null && xmlTextLists != null)
            {
                xmlTextLists.Add(leaf.XmlData.OuterXml);
            }

            if (leaf.ParentExpression.XmlData != null)
            {
                leaf.ParentExpression.XmlData.RemoveChild(leaf.XmlData);
            }

            //删除自身后，同级的、索引大于此叶的所有叶面板索引值应减１.
            //但这段代码应放在DeleteLeaf()方法中而不是此处。
            //因为这个方法是递归删除可能存在的多层。而实际上最终到受影响的只是一层。

            mi.Add(actDelLeaf);
            return true;
        }

        internal LeafPanel InsertSameLevelLeaf(LeafPanel curLeaf, ModifingItem mi)
        {
            if (curLeaf == null || mi == null) return null;

            Expressions.LeafPanel preLevelLeaf = curLeaf.PreLevelLeaf;

            if (preLevelLeaf == null || curLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {
                MessageBox.Show("一个树中只能有一个叶首面板！不能向叶首面板插入“同级”叶。", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }

            Expressions.LeafPanel newLeaf = new LeafPanel(this.RootPanel,
                null, this.Editor, this);

            if (curLeaf.XmlData.InsertXml(Properties.Resources.LeafPanel) == false)
            {
                MessageBox.Show("未能插入新Xml节点！", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }

            XmlNode newNode = curLeaf.XmlData.NextSibling;
            newLeaf.XmlData = newNode;

            newLeaf.LeafType = curLeaf.LeafType;
            newLeaf.Index = curLeaf.Index + 1;
            newLeaf.ParentExpression = this;
            newLeaf.PreLevelLeafExID = curLeaf.PreLevelLeafExID;
            newLeaf.SizeChanged += leaf_SizeChanged;

            Action actInsertTreeLeaf = new Action(
                newLeaf.ExID, -1, newLeaf.GetType().Name, null,
                null, newLeaf.XmlData.OuterXml, ActionType.InsertSameLevelLeaf, this.ExID);

            //解决索引问题。
            List<LeafPanel> sameLevelLeaves = preLevelLeaf.NextLevelLeaves;

            for (int i = 0; i < sameLevelLeaves.Count; i++)
            {
                if (sameLevelLeaves[i].Index > curLeaf.Index)
                {
                    LeafPanel lp = sameLevelLeaves[i];
                    Action actIndex = new Action(lp.ExID,
                        -1, lp.GetType().Name, "Index",
                        lp.Index.ToString(), (lp.Index + 1).ToString());
                    lp.Index++;
                    mi.Add(actIndex);
                }
            }

            this.basePanel.Children.Add(newLeaf);
            this.subPanels.Add(newLeaf);
            sameLevelLeaves.Add(newLeaf);

            mi.NewSelectedExID = newLeaf.ExID;

            mi.Add(actInsertTreeLeaf);

            newLeaf.InvalidateArrange();
            newLeaf.UpdateLayout();

            this.RefreshLayout();
            return newLeaf;
        }

        internal LeafPanel InsertNextLevelLeaf(LeafPanel curLeaf, ModifingItem mi)
        {
            if (curLeaf == null || mi == null) return null;

            Expressions.LeafPanel newLeaf = new LeafPanel(this.RootPanel,
                null, this.Editor, this);
            newLeaf.SizeChanged += leaf_SizeChanged;

            if (curLeaf.XmlData.InsertXml(Properties.Resources.LeafPanel) == false)
            {
                MessageBox.Show("未能插入新Xml节点！", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }

            XmlNode newNode = curLeaf.XmlData.NextSibling;
            newLeaf.XmlData = newNode;

            List<LeafPanel> curNextLevelLeaves = curLeaf.NextLevelLeaves;
            if (curLeaf.LeafType == LeafPanel.LeafPanelType.Root)
            {

                int leftCount = 0; int rightCount = 0;
                foreach (LeafPanel lp in curNextLevelLeaves)
                {
                    switch (lp.LeafType)
                    {
                        case LeafPanel.LeafPanelType.Left:
                            {
                                leftCount++; break;
                            }
                        case LeafPanel.LeafPanelType.Right:
                            {
                                rightCount++; break;
                            }
                    }
                }

                if (leftCount >= rightCount)
                {
                    //右侧优先。
                    newLeaf.LeafType = LeafPanel.LeafPanelType.Right;
                }
                else
                {
                    newLeaf.LeafType = LeafPanel.LeafPanelType.Left;
                }
            }
            else
            {
                newLeaf.LeafType = curLeaf.LeafType;
            }

            newLeaf.Index = curNextLevelLeaves.Count;//添加到所有可能存在的下级叶的尾部。
            newLeaf.ParentExpression = this;
            newLeaf.PreLevelLeafExID = curLeaf.ExID;

            Action actInsertTreeLeaf = new Action(
                newLeaf.ExID, -1, newLeaf.GetType().Name, null,
                null, newLeaf.XmlData.OuterXml, ActionType.InsertNextLevelLeaf, this.ExID);

            this.basePanel.Children.Add(newLeaf);
            this.subPanels.Add(newLeaf);
            curNextLevelLeaves.Add(newLeaf);

            mi.NewSelectedExID = newLeaf.ExID;

            mi.Add(actInsertTreeLeaf);

            newLeaf.InvalidateArrange();
            newLeaf.UpdateLayout();

            this.RefreshLayout(true);
            return newLeaf;
        }

        public LeafPanel PasteLeaf(LeafPanel destLeaf, string clipText, ModifingItem mi)
        {
            if (destLeaf == null || clipText == null || clipText.Length <= 0 ||
                clipText.StartsWith("<TreeLeaves") == false || mi == null ||
                clipText.EndsWith("</TreeLeaves>") == false) return null;

            try
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(clipText);

                XmlNodeList nodes = doc.DocumentElement.ChildNodes;

                if (nodes.Count <= 0)
                {
                    MessageBox.Show("剪贴板中的数据不是叶面板数据。无法完成粘贴。",
                        Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return null;
                }

                //得先处理一下ExID。因为粘贴后可能造成公式的ID重复。
                #region 防止粘贴造成公式间的ID冲突。
                RefreshPreLevelIDs(nodes);
                #endregion

                #region 如果不是粘贴到叶首面板下级，则自动调整方向。
                if (destLeaf.LeafType != LeafPanel.LeafPanelType.Root)
                {
                    XmlAttribute attrLeafType = nodes[0].GetAttribute("LeafType");
                    if (attrLeafType == null)
                    {
                        foreach (XmlNode n in nodes)
                        {
                            n.SetAttribute("LeafType", destLeaf.LeafType.ToString());
                        }
                    }
                    else
                    {
                        if (attrLeafType.Value != destLeaf.LeafType.ToString())
                        {
                            foreach (XmlNode n in nodes)
                            {
                                n.SetAttribute("LeafType", destLeaf.LeafType.ToString());
                            }
                        }
                    }
                }//粘贴到叶首面板下级时，不自动改变方向。
                #endregion

                LeafPanel newPastedStartLeaf = null;

                for (int i = 0; i < nodes.Count; i++)
                {
                    XmlNode node = nodes[i];

                    LeafPanel newLeaf = new LeafPanel(this.RootPanel,
                        null, this.Editor, this);

                    if (this.XmlData.LastChild.InsertXml(node.OuterXml, true))
                    {
                        newLeaf.XmlData = this.XmlData.LastChild;

                        foreach (UIElement ue in newLeaf.BasePanel.Children)
                        {
                            Expressions.Expression ex = ue as Expressions.Expression;

                            if (ex != null)
                            {
                                Expressions.Expression.RebuildAllExIDs(ex);
                            }
                        }

                        if (i == 0)//第一个就是剪切点（或复制点）叶面板。
                        {
                            newLeaf.PreLevelLeafExID = destLeaf.ExID;
                            newLeaf.Index = destLeaf.NextLevelLeaves.Count;
                            //总是粘贴到目标叶面板的下级各叶的尾部。

                            newPastedStartLeaf = newLeaf;
                        }

                        Action actInsertLeaf = new Action(newLeaf.ExID, -1,
                            newLeaf.GetType().Name, null, null,
                            newLeaf.XmlData.OuterXml, ActionType.InsertNextLevelLeaf,
                            this.ExID);

                        mi.Add(actInsertLeaf);

                        this.basePanel.Children.Add(newLeaf);
                        this.subPanels.Add(newLeaf);

                        newLeaf.InvalidateArrange(); newLeaf.UpdateLayout();
                    }
                    else
                    {
                        MessageBox.Show("未能添加Xml节点。粘贴叶面板操作失败！",
                            Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                        return null;
                    }
                }

                RefreshLayout(true);

                return newPastedStartLeaf;
            }
            catch (Exception ex)
            {
                Dialogs.LunarMsgBox.MsgBoxShow(
                    Globals.appName,
                    "未能粘贴叶面板。",
                    "异常消息如下：\r\n" + ex.Message,
                    ex.StackTrace, MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }
        }

        public static void RefreshPreLevelIDs(XmlNodeList nodes)
        {
            for (int i = 0; i < nodes.Count; i++)
            {
                XmlNode node = nodes[i];

                XmlAttribute attrOldExID = node.GetAttribute("ExID");
                if (attrOldExID == null) continue;

                string newID = Guid.NewGuid().ToString();

                for (int j = 0; j < nodes.Count; j++)
                {
                    if (j == i) continue;
                    XmlNode elseNode = nodes[j];

                    XmlAttribute attrElsePreLevelExID = elseNode.GetAttribute("PreLevelLeafExID");
                    if (attrElsePreLevelExID == null) continue;

                    if (attrElsePreLevelExID.Value == attrOldExID.Value)
                    {
                        attrElsePreLevelExID.Value = newID;
                    }
                }

                attrOldExID.Value = newID;
            }
        }

        public override void SetProperty(string propertyName, string value)
        {
            base.SetProperty(propertyName, value);

            switch (propertyName)
            {
                case "LineType":
                    {
                        this.LineType = (TreeLineType)Enum.Parse(typeof(TreeLineType), value);
                        break;
                    }
            }
        }
    }
}
